import 'dart:math';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class GradientBoundDemo extends StatefulWidget {
  GradientBoundDemo({Key? key}) : super(key: key);

  @override
  State<GradientBoundDemo> createState() => _GradientBoundDemoState();
}

class _GradientBoundDemoState extends State<GradientBoundDemo>
    with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller =
        AnimationController(duration: const Duration(seconds: 2), vsync: this);
    animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation(
      parent: controller,
      curve: Curves.linear,
    ))
      ..addListener(() {
        setState(() {});
      });
    controller.repeat();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('渐变边线'),
        systemOverlayStyle: SystemUiOverlayStyle.light,
        backgroundColor: Colors.black87,
      ),
      body: Container(
        margin: EdgeInsets.all(15),
        padding: EdgeInsets.all(5),
        alignment: Alignment.center,
        child: GradientBound(
          colors: [
            Colors.blue,
            Colors.blue[400]!,
            Colors.blue[300]!,
            Colors.blue[100]!,
          ],
          animation: animation.value,
          child: Text(
            '流动的渐变',
            style: TextStyle(
              color: Colors.white,
              fontSize: 20.0,
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

class GradientBound extends StatelessWidget {
  final List<Color> colors;
  final double animation;
  final Widget? child;
  const GradientBound({
    Key? key,
    required this.colors,
    required this.animation,
    this.child,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: GradientBoundPainter(
        colors: colors,
        animation: animation,
      ),
      child: child,
    );
  }
}

class GradientBoundPainter extends CustomPainter {
  final List<Color> colors;
  final double animation;
  const GradientBoundPainter({
    Key? key,
    required this.colors,
    required this.animation,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final rectWidth = 300.0, rectHeight = 200.0;
    // final circleRadius = 80.0;
    Rect rect = Offset(
            size.width / 2 - rectWidth / 2, size.height / 2 - rectHeight / 2) &
        Size(rectWidth, rectHeight);
    final paint = Paint()
      ..shader = LinearGradient(
        begin: Alignment.topCenter,
        end: Alignment.bottomCenter,
        colors: colors,
        transform: GradientRotation(
          animation * 2 * pi,
        ), //改变 transform 的值可以实现渐变旋转效果
      ).createShader(rect)
      ..style = PaintingStyle.stroke
      ..strokeWidth = 8.0;
    canvas.drawRect(rect, paint);
    // canvas.drawCircle(
    //     Offset(size.width / 2, size.height / 2), circleRadius, paint);
  }

  @override
  bool shouldRepaint(covariant GradientBoundPainter oldDelegate) {
    return oldDelegate.colors != colors || oldDelegate.animation != animation;
  }
}

class ScrollGradientTransform extends GradientTransform {
  const ScrollGradientTransform(this.dx, this.dy, this.dz);

  final double dx, dy, dz;

  @override
  Matrix4 transform(Rect bounds, {TextDirection? textDirection}) {
    return Matrix4.identity()..translate(dx, dy, dz);
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    if (other.runtimeType != runtimeType) return false;
    return other is ScrollGradientTransform &&
        other.dx == dx &&
        other.dy == dy &&
        other.dz == dz;
  }

  @override
  int get hashCode => dx.hashCode | dy.hashCode | dz.hashCode;

  @override
  String toString() {
    return '${objectRuntimeType(this, 'ScrollGradientTransform')}(dx: ${debugFormatDouble(dx)}, dy: ${debugFormatDouble(dy)}, dz: ${debugFormatDouble(dz)})';
  }
}
